package snowforce;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;

import snowforce.datatype.HintJSON;
import snowforce.datatype.PassPoint;
import snowforce.datatype.RouteEdgeJSON;
import snowforce.datatype.RouteJSON;
import snowforce.storage.GraphEdgeIdStore;
import snowforce.storage.HintJSONStore;
import snowforce.storage.HintStore;
import snowforce.storage.MapHandlerStore;
import snowforce.storage.PassPointStore;

@Path("/hint")
public class HintService
{
	@GET
	@Produces(MediaType.APPLICATION_JSON)
	public HintJSON getHintJSON(@QueryParam("level") String levelStr, @QueryParam("beginIndex") String beginIndexStr, @QueryParam("endIndex") String endIndexStr, @QueryParam("route") String routesStr)
	{
		System.out.println("EvaluationService");
		System.out.println("levelStr:" + levelStr);
		System.out.println("beginIndexStr:" + beginIndexStr);
		System.out.println("endIndexStr:" + endIndexStr);
		System.out.println("routesStr:" + routesStr);
		HintJSON ret = new HintJSON();
		// ret = getDefault();
		int level, beginIndex, endIndex;
		try {
			level = Integer.parseInt(levelStr);
		}
		catch (Exception e) {
			e.printStackTrace();
			ret.setStatus("PARAM_LEVEL_WRONG");
			return ret;
		}
		try {
			beginIndex = Integer.parseInt(beginIndexStr);
		}
		catch (Exception e) {
			e.printStackTrace();
			ret.setStatus("PARAM_BEGININDEX_WRONG");
			return ret;
		}
		try {
			endIndex = Integer.parseInt(endIndexStr);
		}
		catch (Exception e) {
			e.printStackTrace();
			ret.setStatus("PARAM_ENDINDEX_WRONG");
			return ret;
		}
		if (beginIndex > endIndex) {
			System.out.println("beginIndex>endIndex");
			ret.setStatus("beginIndex>endIndex");
			return ret;
		}
		if (beginIndex > PassPointStore.getStore().get("" + level).size()) {
			System.out.println("no pass point for beginIndex");
			ret.setStatus("no pass point for beginIndex");
			return ret;
		}
		if (endIndex > PassPointStore.getStore().get("" + level).size()) {
			System.out.println("no pass point for endIndex");
			ret.setStatus("no pass point for endIndex");
			return ret;
		}
		List<RouteJSON> routes = new ArrayList<RouteJSON>();
		if (routesStr == null || routesStr.trim().length() < 1) {
			routes = getHintRoutes(level, beginIndex, endIndex);
		}
		else {
			routes = getAdvancedHintRoutes(level, beginIndex, endIndex, routesStr);
		}
		ret = new HintJSON("OK", routes);
		return ret;
	}

	private List<RouteEdgeJSON> getHintJSONList(int level, int beginIndex, int endIndex, String routesStr)
	{
		List<PassPoint> ppl = PassPointStore.getStore().get("" + level);
		List<RouteEdgeJSON> rejl = HintStore.getStore().get("" + level);
		String beginPoint = ppl.get(beginIndex).getPointStr();
		String endPoint = ppl.get(endIndex).getPointStr();
		int index1 = rejl.size() - 1, index2 = 0;
		int i = 0;
		for (Iterator<RouteEdgeJSON> iterator = rejl.iterator(); iterator.hasNext();) {
			RouteEdgeJSON rej = (RouteEdgeJSON) iterator.next();
			String id = rej.getId();
			if ((id.indexOf(beginPoint) == 0 || id.indexOf(beginPoint) == 2) && index1 > i) {
				index1 = i;
			}
			if ((id.indexOf(endPoint) == 0 || id.indexOf(endPoint) == 2) && index2 < i) {
				index2 = i;
			}
			i++;
		}

		return rejl.subList(index1, index2);

	}

	private List<RouteJSON> getHintRoutes(int level, int beginIndex, int endIndex)
	{
		ArrayList<RouteJSON> routes = new ArrayList<RouteJSON>();
		List<List<RouteEdgeJSON>> rejLL = HintJSONStore.getStore().get("" + level);
		List<RouteEdgeJSON> rejL = new ArrayList<RouteEdgeJSON>();
		int index = beginIndex;
		int size = rejLL.size();
		while (index < endIndex && index < size) {
			rejL.addAll(rejLL.get(index));
			index++;
		}
		routes.add(new RouteJSON(rejL));
		return routes;
	}

	private List<RouteJSON> getAdvancedHintRoutes(int level, int beginIndex, int endIndex, String routesStr)
	{
		ArrayList<RouteJSON> routes = new ArrayList<RouteJSON>();
		List<PassPoint> pps = PassPointStore.getStore().get("" + level);
		int endPoint = pps.get(endIndex).getPoint();
		int startPoint = calculateStartPoint(beginIndex, routesStr, pps);
		MapHandler mh = MapHandlerStore.getStore().get("" + level);
		List<Integer> pointList = mh.getShortestPath(startPoint, endPoint);
		RouteJSON routeJSON = convert2RouteJSON(pointList, level + "");
		routes.add(routeJSON);
		return routes;
	}

	private RouteJSON convert2RouteJSON(List<Integer> pointList, String levelStr)
	{
		RouteJSON routeJSON = new RouteJSON();
		List<RouteEdgeJSON> route = new ArrayList<RouteEdgeJSON>();
		Set<String> edgeIdSet = GraphEdgeIdStore.getStore().get(levelStr);
		for (int i = 0; i < pointList.size() - 1; i++) {
			String s1 = pointList.get(i) + "";
			while (s1.length() < 2) {
				s1 = "0" + s1;
			}
			String s2 = pointList.get(i + 1) + "";
			while (s2.length() < 2) {
				s2 = "0" + s2;
			}
			String a = s1 + s2;
			String b = s2 + s1;
			RouteEdgeJSON rej;
			if (edgeIdSet.contains(a)) {
				rej = new RouteEdgeJSON(a);
			}
			else {
				rej = new RouteEdgeJSON(b);
			}
			route.add(rej);
		}
		routeJSON.setRoute(route);
		return routeJSON;
	}

	private int calculateStartPoint(int beginIndex, String routesStr, List<PassPoint> pps)
	{
		int startPoint = pps.get(beginIndex).getPoint();
		if (routesStr != null && routesStr.trim().length() > 0) {
			String[] s = routesStr.split("\\|");
			if (s.length == 1) {
				String edgeId = s[0];
				String pointId1 = edgeId.substring(0, 2);
				String pointId2 = edgeId.substring(2, 4);
				String startPointId = pps.get(beginIndex).getPointStr();
				if (pointId1.equalsIgnoreCase(startPointId)) {
					startPoint = Integer.parseInt(pointId2);
				}
				else {
					startPoint = Integer.parseInt(pointId1);
				}
			}
			else {
				int i = s.length - 1;
				String edgeId = s[i];
				String pointId1 = edgeId.substring(0, 2);
				String pointId2 = edgeId.substring(2, 4);
				if (Util.isEdgeContainPoint(s[i - 1], pointId1)) {
					startPoint = Integer.parseInt(pointId2);
				}
				else {
					startPoint = Integer.parseInt(pointId1);
				}
			}
		}
		return startPoint;
	}

	private HintJSON getDefault()
	{
		HintJSON h = new HintJSON();

		h.setStatus("OK");
		List<RouteJSON> routes = new ArrayList<RouteJSON>();
		RouteJSON route = new RouteJSON();
		List<RouteEdgeJSON> edgeList = new ArrayList<RouteEdgeJSON>();
		RouteEdgeJSON e = new RouteEdgeJSON("01");
		edgeList.add(e);
		e = new RouteEdgeJSON("02");
		edgeList.add(e);
		e = new RouteEdgeJSON("03");
		edgeList.add(e);
		route.setRoute(edgeList);
		routes.add(route);

		route = new RouteJSON();
		edgeList = new ArrayList<RouteEdgeJSON>();
		e = new RouteEdgeJSON("012");
		edgeList.add(e);
		e = new RouteEdgeJSON("023");
		edgeList.add(e);
		e = new RouteEdgeJSON("034");
		edgeList.add(e);
		route.setRoute(edgeList);
		routes.add(route);

		h.setRoutes(routes);
		System.out.println(h);
		return h;
	}

}